package com.hqyg.disjob.register.core.util; import java.util.Date; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.quartz.CronExpression; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.Job; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; import org.quartz.impl.calendar.AnnualCalendar; import org.quartz.impl.matchers.GroupMatcher; import org.quartz.impl.triggers.CronTriggerImpl; import com.hqyg.disjob.common.model.JobInfo; import com.hqyg.disjob.common.util.DateUtil; import com.hqyg.disjob.common.util.LoggerUtil; /** * <pre> * * File: ScheduleUtils.java * * Copyright (c) 2016, globalegrow.com All Rights Reserved. * * Description: * 调度器服务辅助工具实现类 * * Revision History * * Date: 2016年5月25日 * Author: Disjob * * </pre> */ public class ScheduleUtils { /** * 获取触发器key * * @param jobName * @param jobGroup * @return */ public static TriggerKey getTriggerKey(String jobName, String jobGroup) { return TriggerKey.triggerKey(jobName, jobGroup); } /** * 获取jobKey * @param jobName 任务名称 * @param jobGroup 任务组 * @return 根据任务名和任务组生成一个Jobkey */ public static JobKey getJobKey(String jobName, String jobGroup) { return JobKey.jobKey(jobName, jobGroup); } /**检查job是否存在 * @param scheduler 调度器 * @param jobName 任务名称 * @param jobGroup 任务组 * @return 存在返回true,否则返回false */ public static boolean isExistJob(Scheduler scheduler, String jobName, String jobGroup) throws SchedulerException{ if(jobName == null || jobGroup == null) return false; try { return scheduler.checkExists(JobKey.jobKey(jobName, jobGroup)); } catch (SchedulerException e) { return false; } } /** * 获取表达式触发器 * * @param scheduler 调度器 * @param jobName 任务名称 * @param jobGroup 任务组 * @return cron 返回job对应的CronTrigger或null */ public static CronTrigger getCronTrigger(Scheduler scheduler, String jobName, String jobGroup) { try { TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); return (CronTrigger) scheduler.getTrigger(triggerKey); } catch (SchedulerException e) { return null; } } /** * 根据ScheduleJob的相关属性创建job,并放入到调度器中 * @param scheduler 调度器 * @param jobInfo job相关参数 * @throws SchedulerException 处理异常 */ @SuppressWarnings("unchecked") public static void createJob(Scheduler scheduler, final JobInfo jobInfo) throws SchedulerException{ checkJobInfo(jobInfo); LoggerUtil.info("scheduleJob is "+jobInfo); JobDetail jobDetail = JobBuilder.newJob(jobInfo.getJobClass()).withIdentity(jobInfo.getJobName(), jobInfo.getGroupName()) .setJobData(packToJobDataMap(jobInfo)).build(); CronTriggerImpl trigger = null; if(jobInfo.isMisfire()){//错过执行处理策略:从上一次执行的时间开始调度 trigger = (CronTriggerImpl)TriggerBuilder.newTrigger().withIdentity(jobInfo.getJobName(), jobInfo.getGroupName()) .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression()).withMisfireHandlingInstructionIgnoreMisfires()).build(); if(StringUtils.isNoneBlank(jobInfo.getLastFireTime())){//如果存在lastfiretime则代表需要从lastfiretime开始执行错过执行的job try{ String lastFireTime = jobInfo.getLastFireTime(); trigger.setPreviousFireTime(DateUtil.parse(lastFireTime)); trigger.setStartTime(DateUtil.parse(lastFireTime)); AnnualCalendar holidays = new AnnualCalendar(); java.util.Calendar cal = java.util.Calendar.getInstance(); cal.setTime(DateUtil.parse(lastFireTime)); holidays.setDayExcluded(cal, false); trigger.updateWithNewCalendar(holidays, 10);//设置为10ms全局周期,则与trigger策略无关,则会自动的把错过执行的时间段执行 }catch(Exception e){ LoggerUtil.error("job misfire occur error ,lastFireTime is "+jobInfo.getLastFireTime(), e); } } }else{ trigger = (CronTriggerImpl)TriggerBuilder.newTrigger().withIdentity(jobInfo.getJobName(), jobInfo.getGroupName()) .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression()).withMisfireHandlingInstructionDoNothing()).build(); } if(StringUtils.isNoneBlank(jobInfo.getEndTime())){ long endTime = DateUtil.parse(jobInfo.getEndTime()).getTime(); if(endTime > trigger.getStartTime().getTime()){ trigger.setEndTime(new Date(endTime)); } } try { scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { throw new SchedulerException("创建任务失败,"+e.getMessage()); } if(jobInfo.isFireNow()){//是否马上触发 try { scheduler.triggerJob(jobDetail.getKey()); } catch (SchedulerException e) { throw new SchedulerException("任务马上调度执行失败,"+e.getMessage()); } } } private static void checkJobInfo(final JobInfo scheduleJob) throws SchedulerException { if(scheduleJob == null) throw new SchedulerException("请输入参数"); if(scheduleJob.getJobName() == null || scheduleJob.getJobName().length() < 1)//无效 throw new SchedulerException("任务名称无效"); if(scheduleJob.getCronExpression() == null || !CronExpression.isValidExpression(scheduleJob.getCronExpression()))//无效 throw new SchedulerException("groupName:" + scheduleJob.getGroupName() + " jobName:" + scheduleJob.getJobName() + "无效的cron时间表达式: "+scheduleJob.getCronExpression()); if(scheduleJob.getJobClass() == null || !Job.class.isAssignableFrom(scheduleJob.getJobClass()))//为null或不是Job的子类 throw new SchedulerException("无效的JobClass"); } /** * 运行一次任务 * * @param scheduler 调度器 * @param jobName 任务名称 * @param jobGroup 任务组 * @throws SchedulerException 处理异常 */ public static void runOnceJob(Scheduler scheduler, String jobName, String jobGroup) throws SchedulerException{ if(jobName == null || jobName.length() < 1) throw new SchedulerException("任务名称无效"); if(jobGroup == null || jobGroup.length() < 1) throw new SchedulerException("任务组名无效"); JobKey jobKey = JobKey.jobKey(jobName, jobGroup); try { scheduler.triggerJob(jobKey); } catch (SchedulerException e) { throw new SchedulerException("任务运行一次失败,"+e.getMessage()); } } /** * 暂停任务 * @param scheduler 调度器 * @param jobName 任务名称 * @param jobGroup 任务组 * @throws SchedulerException 处理异常 */ public static void pauseJob(Scheduler scheduler, String jobName, String jobGroup) throws SchedulerException{ if(jobName == null || jobName.length() < 1) throw new SchedulerException("任务名称无效"); if(jobGroup == null || jobGroup.length() < 1) throw new SchedulerException("任务组名无效"); JobKey jobKey = JobKey.jobKey(jobName, jobGroup); try { scheduler.pauseJob(jobKey); } catch (SchedulerException e) { throw new SchedulerException("暂停任务失败,"+e.getMessage()); } } /** * 恢复任务 * @param scheduler 调度器 * @param jobName 任务名称 * @param jobGroup 任务组 * @throws SchedulerException 处理异常 */ public static void resumeJob(Scheduler scheduler, String jobName, String jobGroup) throws SchedulerException{ if(jobName == null || jobName.length() < 1) throw new SchedulerException("任务名称无效"); if(jobGroup == null || jobGroup.length() < 1) throw new SchedulerException("任务组名无效"); JobKey jobKey = JobKey.jobKey(jobName, jobGroup); try { scheduler.resumeJob(jobKey); } catch (SchedulerException e) { throw new SchedulerException("恢复任务失败,"+e.getMessage()); } } /** * 删除定时任务 * @param scheduler 调度器 * @param jobName 任务名称 * @param jobGroup 任务组 * @throws SchedulerException 处理异常 */ public static void deleteJob(Scheduler scheduler, String jobName, String jobGroup) throws SchedulerException{ if(jobName == null || jobName.length() < 1) throw new SchedulerException("任务名称无效"); if(jobGroup == null || jobGroup.length() < 1) throw new SchedulerException("任务组名无效"); try { LoggerUtil.info("delete group:"+jobGroup + ",jobName:"+jobName); scheduler.deleteJob(getJobKey(jobName, jobGroup)); } catch (SchedulerException e) { throw new SchedulerException("删除任务失败,"+e.getMessage()); } } /** * 删除任务组的任务 * @param scheduler 调度器 * @param jobGroup 任务组 * @throws SchedulerException 处理异常 */ public static void deleteJobGroup(Scheduler scheduler, String jobGroup) throws SchedulerException{ if(jobGroup == null || jobGroup.length() < 1) return; GroupMatcher<JobKey> matcher = GroupMatcher.jobGroupEquals(jobGroup);//匹配 Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);//查找所有job //scheduler.deleteJobs(jobKeys);批量删除 for (JobKey jobKey : jobKeys) {//循环删除 try { LoggerUtil.info("delete jobkey is "+jobKey.toString()); scheduler.deleteJob(jobKey); } catch (SchedulerException e) { throw new SchedulerException("删除任务失败,"+e.getMessage()); } } } /** * 封包参数,把scheduleJob中的一些参数封装到JobDataMap中返回 * @param scheduleJob 从该对象中区参数 * @return 返回封装了相关参数的JobDataMap */ public static JobDataMap packToJobDataMap(JobInfo scheduleJob){ JobDataMap map = new JobDataMap(); if(scheduleJob != null){ map.put(CoreConstants.JOB_PARAMS, scheduleJob.getParameters()); map.put(CoreConstants.GROUP_NAME, scheduleJob.getGroupName()); map.put(CoreConstants.JOB_NAME, scheduleJob.getJobName()); map.put(CoreConstants.JOB_PATH, scheduleJob.getJobPath()); map.put(CoreConstants.IS_BROADCAST, scheduleJob.isIfBroadcast()); } return map; } /** * 解包JobDataMap,封装相关的参数到ScheduleJob中 * @param scheduleJob job相关参数管理bean * @param from 参数来自JobDataMap对象的相关参数 */ public static void unPackFromJobDataMap(JobInfo scheduleJob,JobDataMap from){ if(scheduleJob != null && from != null){ scheduleJob.setParameters(from.getString(CoreConstants.JOB_PARAMS)); } } }